﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;

namespace CustomScrollBar.DataGridViewScrollBar {
    /// <summary>
    /// DataGridView垂直滚动条
    /// </summary>
    [ToolboxBitmap(typeof(VScrollBar))]
    public partial class DataGridViewVScrollBar : UserControl {

        public DataGridViewVScrollBar() {
            InitializeComponent();
        }

        #region 私有成员
        private System.Windows.Forms.DataGridView SDataGridView = null;
        private Color wakedColor = System.Drawing.Color.FromArgb(((int)(((byte)(158)))), ((int)(((byte)(158)))), ((int)(((byte)(158)))));
        private Color pressedColor = System.Drawing.Color.FromArgb(((int)(((byte)(239)))), ((int)(((byte)(235)))), ((int)(((byte)(239)))));
        private Color enterColor = System.Drawing.Color.FromArgb(((int)(((byte)(158)))), ((int)(((byte)(158)))), ((int)(((byte)(158)))));
        private double StepHeight = 6;
        private System.Timers.Timer TimeDelegate = null;
        private int lines;
        private int TempCursor;
        private bool SlideBarFlag = false;
        private bool ScrollBarFlag = false;
        private int SlideBarOpacity = 255;
        private int MinHeight = 30;
        private double mSense = 0.2;

        private Image upWakeImage = null;
        private Image upEnterImage = null;
        private Image upPressedImage = null;

        private Image downWakeImage = null;
        private Image downEnterImage = null;
        private Image downPressedImage = null;

        /// <summary>
        /// 滑块按下标志
        /// </summary>
        private bool slideBarFlog;
        /// <summary>
        /// 滑块长按线程
        /// </summary>
        private Thread slideBarThread;
        /// <summary>
        /// 上箭头按下标志
        /// </summary>
        private bool upArrowFlog = false;
        /// <summary>
        /// 上箭头长按线程
        /// </summary>
        private Thread upArrowDownThread;
        /// <summary>
        /// 下箭头按下标志
        /// </summary>
        private bool downArrowFlog = false;
        /// <summary>
        /// 下箭头长按线程
        /// </summary>
        private Thread downArrowDownThread;

        #endregion

        #region  滑动灵敏度
        /// <summary>
        /// 滑动灵敏度，1到20之间
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [Category("Appearance")]
        [DefaultValue(null)]
        [Description("1到20之间")]
        public double Sense {
            set {
                mSense = 1 / value;
                this.StepHeight = this.SDataGridView.Font.Height * mSense;
            }
            get {
                return 1 / mSense;
            }
        }
        #endregion

        #region  滑动条最短长度
        /// <summary>
        /// 滑动条最短长度
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [Category("Appearance")]
        [DefaultValue(null)]
        [Description("滑动条最短长度")]
        public int MinSlideBarLenght {
            set {
                MinHeight = value;
            }
            get {
                return MinHeight;
            }
        }
        #endregion

        #region  要滑动的DataGridView
        /// <summary>
        /// 要滑动的DataGridView
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [Category("Appearance")]
        [DefaultValue(null)]
        [Description("要滚动的TreeView")]
        public DataGridView DataGridView {
            set {
                SDataGridView = value;
            }
            get {
                return SDataGridView;
            }
        }
        #endregion

        #region 滑动条被唤醒颜色
        /// <summary>
        /// 滑动条被唤醒颜色
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [Category("Appearance")]
        [DefaultValue(null)]
        public Color WakedColor {
            set {
                wakedColor = value;
            }
            get {
                return wakedColor;
            }
        }
        #endregion

        #region 滑动条被按下颜色
        /// <summary>
        /// 滑动条被按下颜色
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [Category("Appearance")]
        [DefaultValue(null)]
        [Description("滑动条被按下的颜色")]
        public Color PressedColor {
            set {
                pressedColor = value;
            }
            get {
                return pressedColor;
            }
        }
        #endregion

        #region 鼠标进入滑动条颜色
        /// <summary>
        /// 鼠标进入滑动条颜色
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [Category("Appearance")]
        [DefaultValue(null)]
        [Description("鼠标进入滑动条的颜色")]
        public Color EnterColor {
            set {
                enterColor = value;
            }
            get {
                return enterColor;
            }
        }
        #endregion

        #region 上箭头图标

        #region 上箭头的睡眠图标
        /// <summary>
        /// 上箭头的睡眠图标
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [Category("Appearance")]
        [DefaultValue("上箭头的睡眠图标")]
        public Image UpWakeImage {
            set {
                this.upWakeImage = value;
            }
            get {
                return this.upWakeImage;
            }
        }
        #endregion

        #region 上箭头的唤醒图标
        /// <summary>
        /// 上箭头唤醒图标
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [Category("Appearance")]
        [DefaultValue("上箭头的睡眠图标")]
        public Image UpEnterImage {
            set {
                this.upEnterImage = value;
            }
            get {
                return this.upEnterImage;
            }
        }
        #endregion

        #region 上箭头的激活图标
        /// <summary>
        /// 上箭头的激活图标
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [Category("Appearance")]
        [DefaultValue("上箭头的激活图标")]
        public Image UpPressedImage {
            set {
                this.upPressedImage = value;
            }
            get {
                return this.upPressedImage;
            }
        }
        #endregion

        #endregion

        #region 下箭头图标

        #region 下箭头的睡眠图标
        /// <summary>
        /// 下箭头的睡眠图标
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [Category("Appearance")]
        [DefaultValue("下箭头的睡眠图标")]
        public Image DownWakeImage {
            set {
                this.downWakeImage = value;
            }
            get {
                return this.downWakeImage;
            }
        }
        #endregion

        #region 下箭头的唤醒图标
        /// <summary>
        /// 下箭头的唤醒图标
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [Category("Appearance")]
        [DefaultValue("下箭头的唤醒图标")]
        public Image DownEnterImage {
            set {
                this.downEnterImage = value;
            }
            get {
                return this.downEnterImage;
            }
        }
        #endregion

        #region 下箭头的激活图标
        /// <summary>
        /// 下箭头的激活图标
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [Category("Appearance")]
        [DefaultValue("下箭头的激活图标")]
        public Image DownPressedImage {
            set {
                this.downPressedImage = value;
            }
            get {
                return this.downPressedImage;
            }
        }
        #endregion

        #endregion

        /// <summary>
        /// 创建滚动条
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void This_Created(object sender, EventArgs e) {
            this.SlideBar.Size = new Size(this.Width, 40);
            this.SlideBar.BackColor = this.BackColor;
            this.StepHeight = this.SDataGridView.Font.Height * mSense;
            this.upArrow.Image = upWakeImage;
            this.downArrow.Image = downWakeImage;
        }

        /// <summary>
        /// 计算滑块的高度
        /// </summary>
        /// <returns></returns>
        private int SlidebarHeight() {
            int ThumbHeight = 0;
            ThumbHeight = this.SDataGridView.Height * (this.Height - this.upArrow.Height - this.downArrow.Height) /
                              (this.SDataGridView.Rows.GetRowsHeight(DataGridViewElementStates.None) -
                               this.SDataGridView.ColumnHeadersHeight);     //  DataGridView的高度 * 滚动条高度 / DataGridView编辑框中行总高度
            if (ThumbHeight < MinHeight) {
                ThumbHeight = MinHeight;
            }
            return ThumbHeight;
        }

        /// <summary>
        /// 计算滑块的Y位置
        /// </summary>
        /// <returns></returns>
        private int SlidebarPosY() {
            int trackPos = this.SDataGridView.FirstDisplayedScrollingRowIndex;      //trackPos  已经滚动的行数
            int RowCount = this.SDataGridView.RowCount;     //max - min + 1  编辑框总行数
            int page = this.SDataGridView.Rows.GetRowCount(DataGridViewElementStates.Displayed);    //page  编辑框一页可以容纳的行数
            int EmptyHeight = this.Height - this.upArrow.Height - this.downArrow.Height - SlidebarHeight(); //滚动条内空白区域的总高度

            int ThumbPosY = 0;
            if ((RowCount - page) > 0) {
                ThumbPosY = EmptyHeight * trackPos / (RowCount - page) + this.upArrow.Height;
            } else {
                ThumbPosY = EmptyHeight * trackPos + this.upArrow.Height;
            }
            return ThumbPosY;
        }

        /// <summary>
        /// 更新滚动条滑块长度和位置
        /// </summary>
        public void UpdateSlidebar() {
            SlideBar.Size = new Size(SlideBar.Width, SlidebarHeight());
            SlideBar.Location = new Point(SlideBar.Location.X, SlidebarPosY());
        }

        /// <summary>
        /// 鼠标进入滚动条事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScrollBar_MouseEnter(object sender, EventArgs e) {
            SlideBarFlag = true;
            this.UpdateSlidebar();
            this.SlideBar.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(104)))), ((int)(((byte)(104)))), ((int)(((byte)(104)))));
        }

        /// <summary>
        /// 鼠标进入滑块事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SlideBar_MouseEnter(object sender, EventArgs e) {
            this.ScrollBarFlag = true;
            this.UpdateSlidebar();
            this.SlideBar.BackColor = EnterColor;
        }

        /// <summary>
        /// 离开滑块
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SlideBar_MouseLeave(object sender, EventArgs e) {
            this.SlideBar.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(104)))), ((int)(((byte)(104)))), ((int)(((byte)(104)))));
        }

        /// <summary>
        /// 滑块按下拖动事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SlideBar_MouseDown(object sender, MouseEventArgs e) {
            this.SlideBar.BackColor = PressedColor;
            TempCursor = Cursor.Position.Y;
            slideBarFlog = true;
            Control.CheckForIllegalCrossThreadCalls = false;        //确保以线程安全方式访问控件
            slideBarThread = new Thread(() => {
                double a = (double)GetControlScrollLocationMax() / (double)(this.Height - this.downArrow.Height - this.upArrow.Height - this.SlideBar.Height); //控件滚动条的最低位置与自定义滚动条的最低位置比例
                int posmin = this.Height - this.downArrow.Height - SlideBar.Height;
                while (slideBarFlog) {
                    if (Cursor.Position.Y > TempCursor) {
                        if (Cursor.Position.Y >= TempCursor + StepHeight) {
                            TempCursor += (int)StepHeight;
                            if (this.SlideBar.Location.Y + (int)StepHeight <= posmin) //判断是否到达滑块滑动下限
                            {
                                this.SlideBar.Location = new Point(this.SlideBar.Location.X, this.SlideBar.Location.Y + (int)StepHeight);
                                //double a = (double)GetControlScrollLocationMax() / (double)(this.Height - this.downArrow.Height - this.upArrow.Height - this.SlideBar.Height); //控件滚动条的最低位置与自定义滚动条的最低位置比例
                                SetControlScrollLocation((int)((this.SlideBar.Location.Y - this.upArrow.Height) * a) + 3);
                            }
                        }
                    } else {
                        if (Cursor.Position.Y <= TempCursor - StepHeight) {
                            TempCursor -= (int)StepHeight;
                            if (this.SlideBar.Location.Y - (int)StepHeight >= this.upArrow.Height)     //判断是否到达滑块滑动上限
                            {
                                this.SlideBar.Location = new Point(this.SlideBar.Location.X, this.SlideBar.Location.Y - (int)StepHeight);
                                //double a = (double)GetControlScrollLocationMax() / (double)(this.Height - this.downArrow.Height - this.upArrow.Height - this.SlideBar.Height);   //控件滚动条的最低位置与自定义滚动条的最低位置比例
                                SetControlScrollLocation((int)((this.SlideBar.Location.Y - this.upArrow.Height) * a));
                            }
                        }
                    }
                }
            });
            slideBarThread.IsBackground = true;
            slideBarThread.Start();
        }

        /// <summary>
        /// 设置控件的滚动条位置
        /// </summary>
        private void SetControlScrollLocation(int pos) {
            this.SDataGridView.FirstDisplayedScrollingRowIndex = pos;
        }

        /// <summary>
        /// 获取控件滚动条滑动到最下端的位置
        /// </summary>
        /// <returns></returns>
        private int GetControlScrollLocationMax() {
            int posmax = this.SDataGridView.RowCount - this.SDataGridView.Rows.GetRowCount(DataGridViewElementStates.Displayed);
            return posmax;
        }

        /// <summary>
        /// 滑块松开事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SlideBar_MouseUp(object sender, MouseEventArgs e) {
            this.SlideBar.BackColor = EnterColor;
            slideBarFlog = false;
            slideBarThread.Join();
        }

        /// <summary>
        /// 上箭头鼠标点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void upArrow_MouseClick(object sender, MouseEventArgs e) {
            if (this.SlideBar.Location.Y - (int)StepHeight >= this.upArrow.Height) {
                this.SlideBar.Location = new Point(this.SlideBar.Location.X, this.SlideBar.Location.Y - (int)StepHeight);
                double a = (double)GetControlScrollLocationMax() / (double)(this.Height - this.downArrow.Height - this.upArrow.Height - this.SlideBar.Height);   //控件滚动条的最低位置与自定义滚动条的最低位置比例
                SetControlScrollLocation((int)((this.SlideBar.Location.Y - this.upArrow.Height) * a));
            }
        }

        /// <summary>
        /// 下箭头鼠标点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void downArrow_MouseClick(object sender, MouseEventArgs e) {
            if (this.SlideBar.Location.Y + (int)StepHeight <= this.Height - this.downArrow.Height - SlideBar.Height) {
                this.SlideBar.Location = new Point(this.SlideBar.Location.X, this.SlideBar.Location.Y + (int)StepHeight);
                double a = (double)GetControlScrollLocationMax() / (double)(this.Height - this.downArrow.Height - this.upArrow.Height - this.SlideBar.Height);   //控件滚动条的最低位置与自定义滚动条的最低位置比例
                SetControlScrollLocation((int)((this.SlideBar.Location.Y) * a));
            }
        }

        /// <summary>
        /// 上箭头鼠标长按事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void upArrow_MouseDown(object sender, MouseEventArgs e) {
            this.upArrow.Image = this.upPressedImage;
            upArrowFlog = true;
            Control.CheckForIllegalCrossThreadCalls = false;        //确保以线程安全方式访问控件
            upArrowDownThread = new Thread(() => {
                while (this.upArrowFlog != false) {
                    if (this.SlideBar.Location.Y - (int)StepHeight >= this.upArrow.Height) {
                        this.SlideBar.Location = new Point(this.SlideBar.Location.X, this.SlideBar.Location.Y - (int)StepHeight);
                        double a = (double)GetControlScrollLocationMax() / (double)(this.Height - this.downArrow.Height - this.upArrow.Height - this.SlideBar.Height);   //控件滚动条的最低位置与自定义滚动条的最低位置比例
                        SetControlScrollLocation((int)((this.SlideBar.Location.Y - this.upArrow.Height) * a));
                    }
                    Thread.Sleep(50);
                }
            });
            upArrowDownThread.IsBackground = true;
            upArrowDownThread.Start();
        }

        /// <summary>
        /// 上箭头鼠标抬起终止长按事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void upArrow_MouseUp(object sender, MouseEventArgs e) {
            this.upArrow.Image = this.upEnterImage;
            upArrowFlog = false;
            upArrowDownThread.Join();
        }

        /// <summary>
        /// 下箭头鼠标长按事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void downArrow_MouseDown(object sender, MouseEventArgs e) {
            this.downArrow.Image = this.downPressedImage;
            downArrowFlog = true;
            Control.CheckForIllegalCrossThreadCalls = false;        //确保以线程安全方式访问控件
            downArrowDownThread = new Thread(() => {
                while (this.downArrowFlog != false) {
                    if (this.SlideBar.Location.Y + (int)StepHeight <= this.Height - this.downArrow.Height - SlideBar.Height) {
                        this.SlideBar.Location = new Point(this.SlideBar.Location.X, this.SlideBar.Location.Y + (int)StepHeight);
                        double a = (double)GetControlScrollLocationMax() / (double)(this.Height - this.downArrow.Height - this.upArrow.Height - this.SlideBar.Height);   //控件滚动条的最低位置与自定义滚动条的最低位置比例
                        SetControlScrollLocation((int)((this.SlideBar.Location.Y) * a));
                    }
                    Thread.Sleep(50);
                }
            });
            downArrowDownThread.IsBackground = true;
            downArrowDownThread.Start();
        }

        /// <summary>
        /// 下箭头鼠标抬起终止长按事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void downArrow_MouseUp(object sender, MouseEventArgs e) {
            this.downArrow.Image = this.downEnterImage;
            downArrowFlog = false;
            downArrowDownThread.Join();
        }

        /// <summary>
        /// 下箭头鼠标进入
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void upArrow_MouseEnter(object sender, EventArgs e) {
            this.upArrow.Image = this.upEnterImage;
        }

        /// <summary>
        /// 下箭头鼠标离开
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void upArrow_MouseLeave(object sender, EventArgs e) {
            this.upArrow.Image = this.upWakeImage;
        }

        /// <summary>
        /// 上箭头鼠标进入
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void downArrow_MouseEnter(object sender, EventArgs e) {
            this.downArrow.Image = this.downEnterImage;
        }

        /// <summary>
        /// 上箭头鼠标离开
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void downArrow_MouseLeave(object sender, EventArgs e) {
            this.downArrow.Image = this.downWakeImage;
        }
    }
}


